Home |
| Latest | About | Random
# Week 4 Friday Dear Class, Don't forget **HW3** is due tonight at 10pm. Today we discuss from section 9: - Pure function vs procedure - Functions with multiple parameters - What happens when a function is called - Function scope - Assigning argument to parameters - Return and return type - Scope is destroyed - Putting function in another. **For exam on Monday:** - It will be **in-class, 50 minutes**. - Bring your **Bruin Card ID**. - Bring **pencil** or **pen**. - **No notes, no technologies, no shenanigans.** Some advice I have for you is..... What?? A secret message??? What is this?? pagxvwi rwpi hxm htktc hxm htktc hijsn wpgs ndj rpc sd xi cd qgpxcgdi dg ijcv ijcv ijcv hpwjg cd rpe qji egprixrt gtpsxcv rdst axct qn axct rpgtujaan pcs udaadl iwt rdcigda uadl ztte igprz du kpgxpqath pcs epn piitcixdc id hrdet inet xceji qjuutg qddah udg nth cd pcs paa iwpi ypoo zcdl paa iwt sttih lxiw p apjcsgn axhi addz pi iwt das tmpbh pcs iwt egprixrt egdqatbh iwpi yjhi sgdeets dz adrz xc adrz xc qgd htrgti htrgti axcz xc qxd Huh ???? I guess we will have to wait and find out later today! -- [[1-teaching/ucla-2026-fall-pic-10a/practice-1|bonsoon]]. ![[1-teaching/ucla-2026-fall-pic-10a/---files/alan-turing.excalidraw.svg]] %%[[1-teaching/ucla-2026-fall-pic-10a/---files/alan-turing.excalidraw|🖋 Edit in Excalidraw]]%% . . . . . . ## Are you a triangle? Given three sticks with positive lengths `a`, `b`, `c`, can they form a triangle? ![[1-teaching/ucla-2026-fall-pic-10a/---files/is_triangle.excalidraw.svg]] %%[[1-teaching/ucla-2026-fall-pic-10a/---files/is_triangle.excalidraw|🖋 Edit in Excalidraw]]%% To be a triangle, the **sum of any two side must exceed the third**. . . . . . Let's write a function to check! ```cpp #include using namespace std; // 1. declare, also this is the function signature bool is_triangle(double a, double b, double c); int main() { // 3. call the function cout << is_triangle(3, 4, 5) << endl; // 4. Note we can assign the return value // of this function to a variable bool q = is_triangle(67, 67, 67); if (q) { cout << "we have triangle!"; } else { cout << "not a triangle"; } return 0; } // 2. define bool is_triangle(double a, double b, double c) { if ((a + b > c) && (a + c > b) && (b + c > a)) { return true; } else { return false; } } ``` - This function `is_triangle` has three parameters, all `double`s. - The return type of this function is `bool` - The function signature of this function is `bool is_triangle(double, double, double)`. - Can you find another way to re-write that condition checking whether we have a triangle, using `||` and `!` instead? You might want to change the `return` values as well. . . . . . ## Pure functions vs procedures. - A **pure function** is a function that - (1) has no side effects (like printing to console, modifying input buffer, changing variable value even without return value assignment, etc), and - (2) it returns a value, and is not a `void` type function. - A **procedure** is a function that does not return a value (i.e. return type is `void`), but have side effects like printing to console or changing the value of variables. - It is best to be clear which type of function you are writing. Sometimes a function can be neither, it can be helpful but it may be confusing to user. . . . . . Here `bool is_triangle(double a, double b, double c)` is a **pure function**. It returns a value, and it does not modify anything nor have any side effects. However, if we change `is_triangle` to ```cpp void is_triangle(double a, double b, double c) { if ((a + b > c) && (a + c > b) && (b + c > a)) { cout << a << ',' << b << ',' << c << " form a triangle!"; } else { cout << a << ',' << b << ',' << c << " does not form a triangle!"; } } ``` Then this is a **procedure**. It does not have return value and is a void type, but it prints to the console (a side effect). - Also, on **HW3**, you may have used the `std::swap` function from `` header. Do you think this is a pure function or procedure? ```cpp #include #include using namespace std; int main() { int a = 6; int b = 7; cout << a << b << endl; swap(a,b); cout << a << b << endl; return 0; } ``` . . . . If we have `is_triangle` to both print to the screen **and** returns a `bool`, then it is **neither** kinds (but a bit of both): ```cpp bool is_triangle(double a, double b, double c) { if ((a + b > c) && (a + c > b) && (b + c > a)) { cout << a << ',' << b << ',' << c << " form a triangle!"; return true; } else { cout << a << ',' << b << ',' << c << " does not form a triangle!"; return false; } } ``` It can be confusing to the user if we do not document this happens, but it can be useful (say debugging your code) to have a function with return to also print to the screen to see what is happening. . . . . . ## Function scope. With our `bool is_triangle(double a, double b, double c)` function, it makes sense to do: ```cpp double a = 3; double b = 4; double c = 5; cout << is_triangle(a, b, c); ``` But does it make sense to do ```cpp double a = 3; double b = 4; double c = 5; cout << is_triangle(c, a, b); ``` How to decipher above? As it turns out, **when you call a function**: - A **function scope** is created. - Each function parameter variable is created **inside this scope** - Then we assign the values of each **argument** to each **parameter**. - Then we execute the code in the body of the function. - If we hit a `return` keyword, the function stops. - And if it is a non `void` function, we return that value back to the program. It might be **assigned** to another variable waiting, or passed into another function or stream (like `cout << is_triangle(3, 4, 5)`). - End the function and **destroy the function scope!** Pay attention to what is destroyed or not. We can illustrate a function scope with dotted box like scope before. (Check text for illustration) **There is one BIG main difference between function scope and the scope we've encounter so far!!!** - In a function scope, you **can only** use a variable name that is (1) a parameter of the function or (2) declared inside the function scope! A function cannot reach outside of the function scope (Unless we use something called global variables, but we will discourage that from this class and not speak of it). - So if you want to use something from outside the function scope, you have to pass it in as an argument and assign to a parameter of the function! For example, this is a **build error**: ```cpp int f(int x); int main() { int a = 3; int b = 6; return 0; } int f(int x) { return (x+a); // a is not a parameter // nor declared in the function. } ``` . . . . . ## Composing functions together. You can put functions inside functions, so long as they are all declared and defined. Heron of Alexandria came up with a formula for the area of a triangle with side lengths `a`, `b`, `c` as follows $\sqrt{s(s-a)(s-b)(s-c)}$, where `s` is the *semiperimeter* given by $s = \frac{a+b+c}{2}$. Let us write a function to find the area of a triangle formed by three sides `a`, `b`, `c`. But what should we do if the sides don't form a triangle? So first we should check if they form a triangle, and - If so, return the area of the triangle. - If not, we return a **sentinel value** of `-1`, to signal the inputs did not form a triangle. ```cpp #include #include using namespace std; double area_of_triangle(double a, double b, double c); bool is_triangle(double a, double b, double c); int main() { cout << area_of_triangle(3, 4, 5) << endl; cout << area_of_triangle(1, 1, 100) << endl; return 0; } double area_of_triangle(double a, double b, double c) { double s = (a + b + c)/2; if (is_triangle(a, b, c)) { return pow( s * (s-a) * (s-b) * (s-c), 0.5); } else { return -1; } } bool is_triangle(double a, double b, double c) { if ((a + b > c) && (a + c > b) && (b + c > a)) { return true; } else { return false; } } ``` **Remark.** Note how it doesn't even matter if `area_of_triangle` is declared before `is_triangle`, nor if it is defined before it. So long as they are all declared outside before main, and all defined later, it is ok. **Remark.** Since we are doing a bunch of calculations with `double`s, sometimes we will need to worry about precision of `double`. So just keep that in mind in real world situations. . . . . . . ## The cipher text. In the beginning of this lecture you are shown a piece of **cipher text**. As it turns out it is a simple **rotation cipher**, that is, there is a secret key value `k`, where each letter is shifted down by `k` places in the English alphabets, wrapping back around! Spaces are not changed. So if `k = 3`, then `a -> d` and `z -> c`, `y -> b`. Note the English alphabets in order are `abcdefghijklmnopqrstuvwxyz`. What's interesting is that since there are only `26` English alphabets, shifting each letter by `26` places will restore it back. So if the cipher text was obtained by shifting each letter by `k = 3` places, we just need to shift it by `23` more places to restore it. Since we do not know the original shift value, what we can do is a **brute force attack**, by **trying all possible shifts!** Which really are just at most 26 of them. So...... Let's do it! . . . . . Let's write a function called `cipher` that takes in a `string input` and a key value `k`, and returns a `string`. Our rule is: - Go through each character of the `input` string. - Do nothing to the space characters `' '` - For each letter, shift it down by `k`, but wrap around the alphabets - Doing `char` arithmetic will be helpful, as well as the remainder (modulo) `%` operator. Try to build an `output` string according to above rules. Don't forget, we need the `` header to use `string`s! ```cpp #include #include using namespace std; string cipher(string input, int k); int main() { return 0; } string cipher(string input, int k) { string output; for(size_t i = 0; i < input.length(); ++i) { char ch = input.at(i); if (ch == ' ') { output += ch; } else { output += static_cast((ch - 'a' + k) % 26 + 'a'); } } return output; } ``` . . Now test this out. In `main()`, call the function `cipher` by passing in the arguments `"abc"` and `3`. We should get `"def"`. Try it! . . Now, copy paste our cipher text above and store it in a `string` called `message`, say. Then in a loop that goes through all `26` possible key values, print out the shifted cipher text! Try it! It'll look something like this ```cpp string message = "pagxvwi rwpi hxm htktc hxm..." // copy the rest for (int k = 0; k < 26; ++k) { cout << k << endl; // printing the key just to see which one cout << cipher(message, k) << endl << endl; // print shifted message } ``` Now among those messages, one of them should become less garbled! What does it say?? Challenge. - Can you modify it so it can also work with negative key values? - Can you modify it so it also treats CAPITAL letters in a similar way? --- Study hard! You got this! -- [[1-teaching/ucla-2026-fall-pic-10a/practice-1|bonsoon]]